<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <script>
      let st = setTimeout;
      const FULL_FILLED = "fullFilled"; // 成功
      const REJECTED = "rejected"; // 失败
      const PENDING = "pending"; //这里用的setTimeout做异步操作，所以在执行异步之前的时间里，状态都是pending
      let count = 0;
      let Promise = function (fn) {
        //fn就是promise中的函数参数，这个参数有两个内部定义好的resolve和reject函数参数
        this.id = count++;
        this.status = PENDING;
        this.successCallbacks = []; //用来保存then里边的成功回调函数
        this.failedCallbacks = []; //用来保存then里边失败的回调函数

        let resolve = (v) => {
          //promise的resolve执行，后会执行then中的成功回调函数，这个v参数，会传过去
          setTimeout(() => {
            // resolve(value);

            this.value = v;
            this.status = FULL_FILLED; //如果成功会从pending状态变成fullFilled

            this.successCallbacks.forEach((fn) => fn(this.value));
          });
        };
        let reject = (v) => {
          setTimeout(() => {
            // reject(value);
            this.value = v;
            this.status = REJECTED; //失败的话从pending状态变成rejected状态
            this.failedCallbacks.forEach((fn) => fn(this.value));
          });
        };
        try {
          fn(resolve, reject);
        } catch (e) {
          reject(e); // new Promise().then 执行失败
        }
      };
      function excutePromise(promiseOrVal, resolve, reject) {
        //这是第一个参数，是判断then中的返回是一个【promise】还是【普通的基本类型值】
        if (promiseOrVal instanceof Promise) {
          // 还没有写 （then  从promise中取值）
          promiseOrVal.then((v) => {
            excutePromise(v, resolve, reject); //这个就是一直递归判断then中返回的是不是promise还是基本值的函数
          });
        } else {
          // value 基本数据类型
          resolve(promiseOrVal); // then中如果返回的是【基本类型的值】执行resolve函数，就直接进行到下一个的.then的回调函数里面，否则的话就是promise，继续进行循环递归去判断返回的是promise还是基本类型值
        }
      }

      // then 一定是要返回Promise供外部.then
      Promise.prototype.then = function (onFullFilledFn, onRejectedFn) {
        console.log(1);

        let chainPromise; //这个结果就是then的返回值，一定要是promise，供外部的.then
        // 如果当前，3秒以内，状态是【Pending】
        if (this.status === PENDING) {
          //如果是pending状态，就说明，也不知道要走成功还是失败，所以有两种可能
          chainPromise = new Promise((resolve, reject) => {
            // 是pending状态，先把成功或者是失败的回调函数保存起来，等待状态改变后，直接调用，这个目的就是保存函数
            this.successCallbacks.push(() => {
              try {
                setTimeout(() => {
                  // resovle后才会被发布，所执行
                  let value = onFullFilledFn(this.value);
                  // value有可能是Promise, 也有可能是一般的值
                  excutePromise(value, resolve, reject); //这个函数就是去判断返回的值是否是promise还是基本值，基本值的话，就会执行resolve，想定与放行开关，进入到下一个then中
                });
              } catch (e) {
                reject(e);
              }
            });
            this.failedCallbacks.push(() => {
              try {
                setTimeout(() => {
                  // reject后才会被发布，所执行
                  let value = onRejectedFn(this.value);
                  // value有可能是Promise, 也有可能是一般的值
                  excutePromise(value, resolve, reject);
                });
              } catch (e) {
                reject(e);
              }
            });
          });
        }

        if (this.status === FULL_FILLED) {
          //如果状态是成功,直接走成功回调
          chainPromise = new Promise((resolve, reject) => {
            try {
              setTimeout(() => {
                let value = onFullFilledFn(this.value);
                excutePromise(value, resolve, reject);
              });
            } catch (e) {
              reject(e);
            }
          });
        }

        if (this.status === REJECTED) {
          //如果状态是失败
          chainPromise = new Promise((resolve, reject) => {
            try {
              let value = onRejectedFn(this.value);
              excutePromise(value, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        }
        return chainPromise;
      };

      // 模拟3组异步
      // 返回的是Promise实例
      setTimeout(function () {
        console.log("222");
      });
      new Promise(function (resolve, reject) {
        console.log("promise执行了"); //1

        console.log("第1件事。。。"); //2
        resolve("abcd");
        console.log("自己家的");
      }).then((data) => {
        console.log(data);

        return "qaa";
      });
    </script>
  </body>
</html>
